#pragma once
#ifdef _WIN32 /* for Windows Visual Studio */

#include <winsock.h>
#include <WinSock2.h>
#include <io.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include <stdlib.h>
#include <string.h>

SOCKET sock;
#else /* for Linux */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>
#include <ctype.h>
#include <stdlib.h>
#include <errno.h>
#include <getopt.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <netdb.h>
#define stricmp strcasecmp
#define Sleep(ms) usleep((ms)*1000)

#endif

#define MAXN 38         //域名符号种类数
#define LRU_SIZE 10     //LRU缓冲区大小
#define DOMAIN_SIZE 100 //域名串长度
#define wait_queue_size 100

const char *ISPDNSIP = "223.5.5.5";

typedef enum COMMTYPEENUM
{
    TOISPDNS,
    TOCLIENT,
    FROMISPDNS,
    FROMCLIENT,
    INVALID
} COMMTYPE;

typedef UINT64 u64;
typedef UINT32 u32;
typedef UINT16 u16;
typedef UINT8 u8;

static u8 debugMask = 0x00;
//所有的数据结构都是网络序！！！！

typedef struct dnshead
{
    unsigned id : 16;    /* query identification number */
    unsigned rd : 1;     /* recursion desired */
    unsigned tc : 1;     /* truncated message */
    unsigned aa : 1;     /* authoritive answer */
    unsigned opcode : 4; /* purpose of message */
    unsigned qr : 1;     /* response flag */
    unsigned rcode : 4;  /* response code */
    unsigned cd : 1;     /* checking disabled by resolver */
    unsigned ad : 1;     /* authentic data from named */
    unsigned z : 1;      /* unused bits, must be ZERO */
    unsigned ra : 1;     /* recursion available */
    u16 qdcount;         /* number of question entries */
    u16 ancount;         /* number of answer entries */
    u16 nscount;         /* number of authority entries */
    u16 arcount;         /* number of resource entries */
} DH;

typedef struct resourceRecord
{
    u8 *domain;
    u16 rtype;
    u16 rclass;
    u16 ttl;
    u16 rdatalength;
    u8 *rdata;
} RR;

typedef struct questionSection
{
    u8 *qname;
    u16 qtype;
    u16 qclass;

} QS;

typedef struct dnsPacket
{
    struct sockaddr_in sa;
    DH head;
    QS *qd;
    RR *an;
    RR *ns;
    RR *ar;
    int time;
} DP;

typedef struct Trie
{
    Trie *next[MAXN];
    int count;
    char ip[16];
} Trie;

Trie *local_root, *LRU_root; //分别是本地DNS表的树根，LRU的树根
char LRU_queue[LRU_SIZE][DOMAIN_SIZE];
char wait_queue[wait_queue_size][DOMAIN_SIZE];
unsigned int LRU_queue_head = 0, LRU_is_flush = 0;
int wait_queue_head = -1, wait_queue_tail = -1;

int tag(char v);

void in_wait_queue(char *domain, unsigned id);

void node_insert(char *domain, char *ip_2_insert, Trie **root_ptr);

char *node_find(char *domain, Trie **root_ptr);

char *domain_search(); //用于查询域名返回ip。成功返回ip，失败返回NULL

void node_delete(char *s, Trie **root_ptr);

void LRU_insert(char *domain, char *ip_2_insert); //用于插入上级DNS返回的ip以及域名

void config(int, char **);

void release(DP *); //一定要用这个释放啊！！！！！